import { onMounted, Ref, ref, unref, watch } from 'vue'
import { useMessage } from '/@/hooks/web/useMessage'

const { createMessage } = useMessage()

export interface ResponseDataType<T = any> {
  data: T
  meta: { total: number }
}

export interface ExportLinkType {
  link: string
}

export interface MessageType {
  GET_DATA_IF_FAILED?: string
  GET_DATA_IF_SUCCEED?: string
  EXPORT_DATA_IF_FAILED?: string
  EXPORT_DATA_IF_SUCCEED?: string
}

export interface ListReturn<T = any> {
  data: T[]
  total: number
}

interface OptionsType<T = any> {
  requestError?: () => void
  requestSuccess?: (result: any) => void
  exportError?: () => void
  exportSuccess?: () => void
  filterOption?: Ref<T>
  transformFn?: (...args: any[]) => ListReturn
  exportRequestFn?: (...args: any) => Promise<ResponseDataType<ExportLinkType>>
  message?: MessageType
  preRequest?: (...args: any[]) => void
  immediate?: boolean
  defaultFilterOption?: Ref<T>
}

export interface MessageType {
  GET_DATA_IF_FAILED?: string
  GET_DATA_IF_SUCCEED?: string
  EXPORT_DATA_IF_FAILED?: string
  EXPORT_DATA_IF_SUCCEED?: string
}

const DEFAULT_MESSAGE: MessageType = {
  GET_DATA_IF_FAILED: '数据获取失败',
  EXPORT_DATA_IF_FAILED: '导出失败',
}

export function useList<T extends (...args: any) => Promise<ResponseDataType<any>>>(
  listRequestFn: T,
  options: OptionsType = {}
) {
  const {
    immediate = true,
    preRequest,
    message = DEFAULT_MESSAGE,
    filterOption = ref({}),
    exportRequestFn = undefined,
    transformFn = undefined,
    defaultFilterOption = unref({}), // 默认的参数，不会清空
  } = options
  filterOption.value = { ...defaultFilterOption, ...filterOption.value }
  const { GET_DATA_IF_FAILED, EXPORT_DATA_IF_FAILED } = message
  // 加载态
  const loading = ref(false)
  // 当前页
  const curPage = ref(1)
  // 总
  const total = ref(0)
  // 分页大小
  const pageSize = ref(10)
  // 数据
  const list = ref<Awaited<ReturnType<typeof listRequestFn>>['data']>([])

  const loadData = (page = curPage.value, size = pageSize.value) => {
    if(loading.value) return Promise.resolve({ list: [], total: 0 })
    // 兼容page可能是event
    const requestPage = typeof page === 'object' ? unref(curPage) : page
    if (page !== curPage.value) return curPage.value = page;
    return new Promise(async resolve => {
      if (loading.value) return resolve({ list: [], total: 0 })
      loading.value = true
      try {
        // 在这之前的钩子
        preRequest?.()

        const result = await listRequestFn({
          pageSize: size,
          pageNum: requestPage,
          ...defaultFilterOption,
          ...filterOption.value,
        })
        const transformResult = transformFn ? transformFn(result) : result
        const { data } = transformResult || {}

        let count = 0
        if ('total' in transformResult && transformResult.total) {
          count = transformResult.total
        }
        list.value = data
        total.value = Number(count)
        options?.requestSuccess?.(result)
        resolve({
          list: data,
          total: count,
        })
      } catch (error) {
        if (GET_DATA_IF_FAILED) {
          createMessage.error(GET_DATA_IF_FAILED)
        }
        options?.requestError?.()
      } finally {
        loading.value = false
      }
    })
  }
  const reset = (notReset: any = {}) => {
    if (!filterOption.value) return
    const keys = Reflect.ownKeys(filterOption.value)
    keys.forEach(key => {
      Reflect.set(filterOption.value, key, undefined)
    })
    filterOption.value = { ...defaultFilterOption, ...notReset }
    loadData(1)
  }

  const exportFile = async () => {
    if (!exportRequestFn && typeof exportRequestFn !== 'function') {
      throw new Error('当前没有提供exportRequest函数')
    }
    try {
      const {
        data: { link },
      } = await exportRequestFn(filterOption.value)
      window.open(link)
      options?.exportSuccess?.()
    } catch (error) {
      if (EXPORT_DATA_IF_FAILED) {
        createMessage.error(EXPORT_DATA_IF_FAILED)
      }
      options?.exportError?.()
    }
  }

  // 监听分页数据改变
  watch([curPage, pageSize], () => {
    loadData(curPage.value)
  })

  onMounted(() => {
    if (immediate) {
      loadData(curPage.value)
    }
  })

  return {
    loading,
    curPage,
    total,
    list,
    filterOption,
    defaultFilterOption,
    reset,
    pageSize,
    exportFile,
    loadData,
  }
}
